Úvod


KAPITOLA 3

PRÁCE S DATY 1

V předchozích dvou kapitolách jsme získali úvodní přehled o práci v R, respektive RStudiu, a proto se nyní můžeme pustit do vlastní analýzy dat.

Projdeme si základní statistické testy, na něž navážeme příkazy table a summarize. Díky nim se naučíte, kterak lze v krátkém čase získat z dat velice hodnotné informace. Načtěte databázi Katan, jdeme si hrát.

Statistika 1

Column

Medellín: Statistika 1

Ačkoliv třetí kapitolu začínáme v Medellínu, které se stalo za dob drogového magnáta Pablo Escobara jedním z nejnebezpečnějších měst v Jižní Americe, není se čeho obávat. Překonejme tedy svůj strach a vrhněme se do útrob této kapitoly.

Popisné statistiky nás budou obdobně jako matematické operace provázet po celou dobu naší práce v R. Pojďme se nyní seznámit s těmi, které jsme na naší cestě prozatím nepotkali. Začněme příkazem summary(). S jeho pomocí zjistíme základní statistické údaje (průměr, medián, minimum, maximum, dolní kvartil a horní kvartil) pro numerické proměnné databáze. Přitom nám tato funkce prozradí i datové typy jednotlivých sloupců včetně jejich délky, která je nicméně u data frame vždy stejná (viz předchozí kapitola).

summary(Katan)
     Partie           Věk          Pohlaví            Vzdělání        
 Min.   :1.000   Min.   :13.00   Length:200         Length:200        
 1st Qu.:1.000   1st Qu.:20.75   Class :character   Class :character  
 Median :3.000   Median :25.00   Mode  :character   Mode  :character  
 Mean   :3.095   Mean   :27.64                                        
 3rd Qu.:4.000   3rd Qu.:32.00                                        
 Max.   :9.000   Max.   :75.00                                        
    Kolej              Práce             Kouření              Klub          
 Length:200         Length:200         Length:200         Length:200        
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
      Děti     
 Min.   :0.00  
 1st Qu.:0.00  
 Median :0.00  
 Mean   :0.66  
 3rd Qu.:1.00  
 Max.   :4.00  

Zvídavé studenty jistě tíží otázka, co se stane v případě, použijeme-li příkaz summary() nikoliv pro data frame, ale pro vektor či dílčí proměnnou datové tabulky (např. summary(Katan$Pohlaví))? Na výsledek takového příkazu si ještě chvíli počkejme, jelikož se jím budeme samostatně zabývat v následující lekci.

Dalšími užitečnými příkazy v naší práci s daty bezpochyby budou min(), max(), range() a quantile(). Range v angličtině znamená rozmezí, proto nás v tuto chvíli již asi nepřekvapí, co zajímavého tato funkce dovede. Příkaz quantile() nám kromě minima a maxima zjistí též dolní kvartil (25. percentil dat), medián a horní kvartil (75. percentil dat) numerické proměnné.

min(Katan$Věk)  # minimum proměnné Věk v souboru Katan
[1] 13
max(Katan$Věk)  # maximum proměnné Věk v souboru Katan
[1] 75
range(Katan$Věk)    # minimum a maximum proměnné Věk v souboru Katan
[1] 13 75
quantile(Katan$Věk) 
# minimum, dolní kvartil, medián, horní kvartil a maximum proměnné Věk
   0%   25%   50%   75%  100% 
13.00 20.75 25.00 32.00 75.00 

Chceme-li zjistit nejenom kvartily, ale například i kvintily, jež rozdělují soubor dat na pětiny, budeme muset využít v rámci příkazu quantile() jeho parametr probs.

quantile(
    Katan$Věk, 
    probs = c(0, 0.2, 0.4, 0.6, 0.8, 1))
  0%  20%  40%  60%  80% 100% 
  13   19   23   27   34   75 

Osadníci z Katanu jsou hrou pro celou rodinu, o čemž svědčí fakt, že nemladšímu osadníkovi je 13 let a nejstaršímu dokonce 75 let. Jaký je však věkový průměr všech respondentů naší databáze? S příkazem mean() (průměr) jsme se na rozdíl od příkazu median() již setkali. Přesto v jeho zápisu nalezneme něco nového a tím je parametr na.rm = TRUE. Bohužel ne vždy budeme obšťastněni absencí chybějících hodnot v datovém souboru, tak jako v databázi Katan. Aby však funkce mean() mohla správně pracovat i tehdy, máme-li v proměnné prázdné buňky, je nutné příkazu sdělit, že chybějící hodnoty musí přeskočit. V opačném případě by následoval neúprosný error. Parametr na.rm = TRUE využijeme nejenom u průměru či mediánu, ale i u dalších příkazů, na které ještě narazíme. Formát zápisu na.rm = TRUE vychází z té podstaty, že chybějící buňky jsou v R pojmenovány jako NA (Not Available), zatímco rm značí příkaz pro mazání.

mean(Katan$Věk, na.rm = TRUE)
[1] 27.64
median(Katan$Věk, na.rm = TRUE)
[1] 25

Když už jsme narazili na téma chybějících dat, podívejme se i na příkaz complete.cases(). Ten totiž dokáže vymazat veškeré řádky v data frame, ve kterých nalezne alespoň jednu chybějící hodnotu. Abychom si tento příkaz mohli prakticky vyzkoušet, musíme si nějaké chybějící hodnoty nejdříve vytvořit. K tomu využijeme příkaz edit(), se kterým jsme se seznámili v předchozí kapitole.

DirtyKatan <- edit(Katan)

Máme-li už alespoň několik hodnot v Katanu přetvořených na NA (k NA nepřidávejte žádné uvozovky ani apostrofy), můžeme si vyzkoušet následující dvě varianty příkazu complete.cases(). Pomocí první z nich vytvoříme logický vektor TRUE/FALSE a pomocí té druhé získáme data frame s názvem CleanKatan, který bude očištěn od řádků, ve kterých byla nalezena alespoň jedna chybějící hodnota.

CompleteVectorKatan <- complete.cases(DirtyKatan)
# Pomocí tohoto příkazu získáme logický vektor ve tvaru 
# TRUE/FALSE, kde TRUE značí řádky bez chybějících údajů.

CleanKatan <- DirtyKatan[complete.cases(DirtyKatan), ]
# Zde získáme databázi CleanKatan obsahující pouze úplné řádky.
# Srovnej předchozí dva příkazy s následujícími příkazy, 
# se kterými jsme se poprvé setkali v Panamě.

Katan[ , 1] >= 5
# vs
Katan[Katan[ , 1] >= 5, ]

Vraťme se zpět k mean() a podívejme se, kterak lze zjistit průměr nejenom uvnitř proměnné, ale i mezi sloupci. Pro ilustraci si předveďme následující příklad. Vytvořme si datovou tabulku, jež bude obsahovat známky na vysvědčení z chemie, fyziky a biologie nejmenovaného hypotetického studenta z nejmenovaných let jeho dávného studia. Naším úkolem bude spočítat studijní průměry v jednotlivých pololetích za tyto tři přírodovědné předměty, v nichž náš hypotetický student nikdy příliš neexceloval.

# vzorový data frame
známky <- data.frame(
  chemie = c(2, 3, 3, 3, 2, 3, 2, 3, 3, 4, 4, 3, 3, 4),
  fyzika = c(2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 3, 2),
  biologie = c(2, 3, 3, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3))

# výpočet průměru mezi proměnnými
Průměr <- rowMeans(známky[ ,1:3])   
 [1] 2.000000 2.666667 2.666667 2.333333 2.000000 2.000000 2.000000 2.333333
 [9] 2.666667 2.666667 3.000000 2.666667 2.666667 3.000000

Příkaz, se kterým jsme výše uvedený příklad vypočítali, se nazývá rowMeans() (máte-li problém s angličtinou, row znamená řádek a column naopak sloupec). Při jeho zápisu si dávejme pozor na velké M a malé s na jeho konci. Skladba tohoto příkazu je taková, že do kulaté závorky uvádíme výběr sloupců, mezi kterými chceme průměr spočítat. Jelikož chceme počítat průměr po řádcích u proměnných z prvního až třetího sloupce, musíme do závorky nejdříve uvést čárku (nezapomínejte na formát zápisu [řádky, sloupce]) a teprve až poté čísla jedna a tři (do zápisu by místo příkazu 1:3 šlo zapsat též i c(1, 2, 3)).

Stejně jako průměr, lze i součet jednotlivých proměnných provést v obdobném formátu. Pouze místo Means použijeme analogické Sums.

Součet <- rowSums(známky[ ,1:3])    
# příkaz vypočítá součet mezi sloupci po řádcích 
# pozor na s na konci a velké S oproti sum
 [1] 6 8 8 7 6 6 6 7 8 8 9 8 8 9

Ne vždy je ale nutné pokoušet se o co nejsofistikovanější styl zápisu, jelikož v jednoduchosti se skrývá síla.

Součet <- známky$chemie + známky$fyzika + známky$biologie
 [1] 6 8 8 7 6 6 6 7 8 8 9 8 8 9

Znalosti z předchozích kapitol a šesté třídy základní školy by vám měly vystačit i pro výpočet průměru.

Průměr <- (známky$chemie + známky$fyzika + známky$biologie)/3
 [1] 2.000000 2.666667 2.666667 2.333333 2.000000 2.000000 2.000000 2.333333
 [9] 2.666667 2.666667 3.000000 2.666667 2.666667 3.000000

V rámci statistického zpracování dat se budeme často potýkat nejenom s obyčejným průměrem, ale i rozptylem, směrodatnou odchylkou či korelací. Zatímco však na rozptyl a směrodatnou odchylku, nejste-li statistici, můžete v klidu zapomenout, korelaci byste v této lekci přeskakovat neměli.

var(Katan$Věk) # příkaz vypočítá rozptyl proměnné Věk
[1] 126.9049
sd(Katan$Věk) # příkaz vypočítá směrodatnou odchylku proměnné Věk
[1] 11.26521
cor(Katan$Věk, 
    Katan$Partie) # příkaz vypočítá korelaci mezi proměnnými Věk a Partie
[1] -0.5375447

Korelace označuje sílu vazby mezi dvěma proměnnými, která je charakterizována číslem od nuly do jedné (plusové znaménko značí pozitivní vazbu, negativní zápornou). Pokud se tedy jedna z proměnných pohybuje jedním či druhým směrem, mění se dle síly vazby i ta druhá a naopak. Dávejte si však pozor na to, že z korelace nelze určit kauzalitu, tj. nepoznáme z ní, kdo koho ve skutečnosti ovlivňuje. Dále není možné zapomenout, že přímá vazba mezi proměnnými může být pouze zdánlivá, jelikož zde může působit třetí zprostředkující proměnná.

Podobně jako u funkce mean(), bohužel i u korelace nás budou často obtěžovat chybějící hodnoty. V takovém případě však nebude možné využít parametr na.rm = TRUE, nýbrž use = "complete.obs". U korelace totiž nepracujeme s jednou, ale dvěma proměnnými.

cor(
  Katan$Věk, 
  Katan$Partie, 
  use = "complete.obs") 
[1] -0.5375447

S obyčejnou korelací velmi těsně souvisí i jeho neparametrická varianta, jež se nazývá Spearmanův korelační koeficient. Ten vypočítáme pomocí následujícího příkazu.

cor(
  Katan$Věk, 
  Katan$Partie, 
  method = "spearman", 
  use = "complete.obs")
[1] -0.7026785

Setkáváte se se Spearmanovým koeficientem poprvé? Spearman nevychází ze samotných hodnot jako běžná korelace, ale z jejich pořadí. Představte si například soutěž v krasobruslení, ve které rozhodují dva rozhodčí, kteří rozdělí dvacet závodnic podle jejich výkonu od nejlepší po nejhorší krasobruslařku. Naším úkolem následně bude zjistit, jak moc byli tito dva rozhodčí ve svém posuzování rozdílní. Nebude nás proto zajímat samotná velikost známky, kterou daná krasobruslařka získala, nýbrž její pořadí mezi ostatními sportovkyněmi. Spearmanův koeficient nicméně stejně jako běžná korelace nabývá hodnot od nuly do jedné (respektive od mínus jedné do jedné, abychom byli naprosto přesní).

Body <- data.frame(
  Rozhodčí_Karel = c(1, 5, 3, 2, 12, 15, 4, 7, 8, 11, 
                     9, 13, 20, 19, 6, 10, 14, 16, 17, 18),
  Rozhodčí_Jarda = c(1, 4, 3, 5, 11, 15, 2, 8, 13, 12, 
                     9, 7, 20, 19, 14, 10, 6, 18, 16, 17),
  Krasobruslařky = c("Barunka", "Karlička", "Zuzanka", "Alžbětka", 
                     "Petruška", "Jája", "Pája", "Pavlínka", 
                     "Věruška", "Helča", "Maruška", "Anička", 
                     "Anežka", "Esterka", "Mariánka", "Verunka", 
                     "Marfuška", "Boženka", "Jiřinka", "Pepička"))
# proměnné Rozhodčí obsahují pořadí krasobruslařek dle rozhodčích

cor(
  Body$Rozhodčí_Karel, 
  Body$Rozhodčí_Jarda, 
  method = "spearman", 
  use = "complete.obs")
[1] 0.8406015

Spearmanův korelační koeficient činí 0.84, což značí velice silnou závislost (viz následující tabulka). Jarda s Karlem si proto mohou v klidu podat ruce, jelikož jejich hodnocení krasobruslařek není příliš rozdílné.

Absolutní    |
hodnota      | Interpretace
korelace     | 
--------------------------------------------
0.010.09  | triviální nebo žádná korelace    
0.100.29  | nízká korelace
0.300.49  | střední korelace
0.500.69  | podstatná korelace
0.700.89  | velmi silná korelace
0.901.00  | téměř perfektní korelace

Pro kontrolu předchozího výpočtu si vypočítejme ještě běžný korelační koeficient. Je-li totiž výše uvedený výsledek správný, měla by hodnota korelačního koeficientu nabývat stejné hodnoty jako u Spearmana. Proč? V příkladu s krasobruslařkami jsme totiž vytvořili data frame, který již obsahoval pořadí závodnic, a nikoliv jejich známky získané od rozhodčích, od nichž by se pořadí teprve odvíjelo.

cor(
  Body$Rozhodčí_Karel, 
  Body$Rozhodčí_Jarda)
[1] 0.8406015

Výsledek je stejný, přejděme tedy s klidným srdcem k četnostním tabulkám (table a summary). Před tím se nicméně nezapomeňte podívat na příklady k procvičení. Na závěr ještě zmíním, že statistickým testům bude věnována jedna kompletní lekce v osmé kapitole (Dillí). Máte se věru na co těšit.

Column

Příklady

Příklad 1

Vypočítejte průměr proměnné Partie z databáze Katan. Uvažujte případ, že máte v databázi chybějící údaje.

Příklad 2

Vypočítejte minimum a maximum proměnné Partie.

Příklad 3

Vypočítejte korelační koeficient mezi proměnnými Věk a Děti.

Příklad 4

Vypočítejte body mass index (hmotnost v kg/výška v m umocněná na druhou) pro následující databázi BMI. Výsledný vektor připojte ke stávající databázi BMI.

BMI <- data.frame(
  Hmotnost = c(60, 50, 49, 80, 90, 48, 
               63, 53, 75, 81),
  Výška = c(170, 166, 155, 190, 178, 
            158, 168, 163, 170, 185))

Table a summary

Column

Lima: Table a summary

Četnostní tabulky jsou v rámci statistiky zcela nepostradatelnou záležitost. Představte si například, že pracujete s databází, jež obsahuje desetitisíce hodnot o zemědělcích a vy si přejete vědět, kolik jedinců z nich tvoří chovatelé lam (jsme v Peru). Jak na to? Tužka a papír? To jistě ne. Mnohem rychlejší bude využít příkaz summary() nebo table(). My sice desetitisíce hodnot v naší databázi Katan nemáme, přesto nám summary() a table()ušetří spoustu času. Podívejme se nejdříve na formát zápisu u summary(). V něm však nebudeme řešit lamy, ale muže a ženy.

summary(Katan$Pohlaví)
 muž žena 
 142   58 

Jak je vidět, Osadníci z Katanu přitahují více osadníků nežli osadnic. Některým z Vás ale výše uvedený příkaz fungovat nebude. V případě, že je totiž proměnná Pohlaví datového typu character a nikoliv faktor, uzříte na svém monitoru následující výstup z konzole.

summary(Katan$Pohlaví)
   Length     Class      Mode 
      200 character character 

V rámci příkazu table() datový typ proměnné řešit nemusíme. Bude tak pro většinu z nás jistě mnohem přitažlivější.

table(Katan$Pohlaví) 

 muž žena 
 142   58 

Jaký výstup nás ale bude očekávat v případě chybějících hodnot v databázi? Podívejme se na rozdíl mezi summary() a table().

# Nejdříve si vytvoříme chybějící hodnoty, a teprve až poté 
# využijeme summary().
Katan$Pohlaví[1] <- NA
summary(Katan$Pohlaví)
 muž žena NA's 
 142   57    1 
Katan$Pohlaví[1] <- NA
table(Katan$Pohlaví) 

 muž žena 
 142   57 

Příkaz summary() nám na rozdíl od table() ukáže nejenom četnost mužů a žen, ale i počet chybějících hodnot. Table() chybějící hodnoty automaticky přeskočí. Ačkoliv je tato skutečnost obecně spíše výhodná, nesmíme na ni zapomenout. Za krátkou chvíli si ukážeme příklad takové situaci, ve které by její opomenutí mohlo způsobit potíže. Prozatím ale pokračujme dál a ukažme si, jak pracuje table() u numerických proměnných.

Chceme-li například zjistit počty hráčů Osadníků podle množství sehraných partií, stačí zapsat následující příkaz. Díky němu poznáme, že necelá polovina respondentů naší databáze odehraje za měsíc maximálně dvě partie této úžasné deskové hry.

table(Katan$Partie)

 1  2  3  4  5  6  7  8  9 
54 44 39 19 14 10  9  8  3 

V případě, že bychom u numerické proměnné použili příkaz summary(), získali bychom přehled o základních statistických údajích, tj. průměru, mediánu či jednotlivých kvantilech proměnné (srovnej s předchozí lekcí a příkazem summary(Katan)).

summary(Katan$Partie)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   1.000   3.000   3.095   4.000   9.000 

Vraťme se však zpět k pohlaví hráčů a hráček Osadníků a pokusme se zjistit jejich jednotlivé podíly v databázi. Kolik procent hráčů tvoří něžné pohlaví? Tak na tuto otázku nám odpoví následující skript.

table(Katan$Pohlaví)/length(Katan$Pohlaví)

 muž žena 
0.71 0.29 

Naše genderově nevyvážená databáze obsahuje bohužel pouze 29 % osadnic. Ženy, kde jste?

Stejný formát zápisu lze samozřejmě použít i pro numerickou proměnnou.

table(Katan$Partie)/length(Katan$Partie)

    1     2     3     4     5     6     7     8     9 
0.270 0.220 0.195 0.095 0.070 0.050 0.045 0.040 0.015 

Na scénu opět přichází hypotetická otázka od zvídavého studenta. Je možné výše uvedený příkaz použít i tehdy, máme-li v databázi chybějící hodnoty? Odpověď je jednoduchá, není. Důvod je prostý. Příkaz table(), jak již víme, nezapočítává chybějící hodnoty. Příkaz length() nicméně tyto hodnoty do délky proměnné započítá. Musíme je tudíž od něj odečíst a to například pomocí příkazu sum() či samotného length(). Ukažme si vše na proměnné Pohlaví.

Katan$Pohlaví[1] <- NA

# nejdříve s využitím příkazu length()
table(Katan$Pohlaví)/length(Katan$Pohlaví[!is.na(Katan$Pohlaví)])
# Pozor: nelze použít následující příkaz!
# length(!is.na(Katan$Pohlaví))

# nyní s pomocí sum()
table(Katan$Pohlaví)/(length(Katan$Pohlaví)-sum(is.na(Katan$Pohlaví)))

# anebo ještě třeba takto, možností je mnoho
table(Katan$Pohlaví)/sum(!is.na(Katan$Pohlaví))

      muž      žena 
0.7135678 0.2864322 

V příkazech jste si jistě všimli označení !is.na (respektive is.na), co znamená? Jedná se o funkci, která dokáže detekovat chybějící hodnoty (respektive nechybějící hodnoty). V případě, že námi zkoumaná proměnná chybějící hodnoty obsahuje a naším cílem je zjistit počet těchto hodnot, využijeme tuto funkci a vložíme ji do příkazu lenght() či sum(). S funkcí is.na se v této lekci ještě potkáme, a to v rámci tzv. logických operátorů.

A jaká je vlastně myšlenka příkazu length(Katan$Pohlaví[!is.na(Katan$Pohlaví)])? Příkaz length(Katan$Pohlaví) jistě není třeba blíže vysvětlovat. Ten však nelze použít, jelikož by spočítal počet všech hodnot v proměnné Pohlaví, což není naším cílem, protože v této proměnné existují chybějící hodnoty. Z tohoto důvodu bude naším úkolem vymyslet takový zápis, který pro length() použije pouze hodnoty rozdílné od NA. S výběrem hodnot jsou spojené hranaté závorky. Pokud bychom například chtěli vybrat první hodnotu z proměnné Pohlaví, zapsali bychom do R Katan$Pohlaví[1] (obdobně jako u vektorů). Čísla uvnitř hranatých závorek nám ale pro výběr hodnot rozdílných od NA nepomohou, proto musíme povolat do služby logický vektor, který rozhodne, která z hodnot ve sloupci Pohlaví nabývá NA, a která naopak obsahuje skutečné pozorování. K tomu nám nejlépe poslouží příkaz !is.na(Katan$Pohlaví). Ten následně vložíme do hranatých závorek, z čehož vznikne příkaz Katan$Pohlaví[!is.na(Katan$Pohlaví)].

!is.na(Katan$Pohlaví)
  [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [13]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [25]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [37]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [49]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [61]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [73]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [85]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [97]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[109]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[121]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[133]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[145]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[157]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[169]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[181]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[193]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
Katan$Pohlaví[!is.na(Katan$Pohlaví)]
  [1] "žena" "muž"  "muž"  "muž"  "muž"  "muž"  "žena" "žena" "žena" "muž" 
 [11] "muž"  "žena" "žena" "muž"  "muž"  "muž"  "žena" "muž"  "muž"  "žena"
 [21] "muž"  "muž"  "muž"  "žena" "muž"  "muž"  "muž"  "žena" "žena" "muž" 
 [31] "žena" "žena" "muž"  "žena" "žena" "žena" "muž"  "muž"  "žena" "žena"
 [41] "žena" "muž"  "žena" "muž"  "žena" "muž"  "muž"  "žena" "žena" "muž" 
 [51] "muž"  "muž"  "muž"  "muž"  "žena" "muž"  "muž"  "muž"  "žena" "žena"
 [61] "žena" "muž"  "muž"  "muž"  "muž"  "žena" "žena" "muž"  "muž"  "muž" 
 [71] "muž"  "žena" "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž" 
 [81] "žena" "muž"  "muž"  "muž"  "žena" "muž"  "žena" "muž"  "žena" "muž" 
 [91] "muž"  "muž"  "muž"  "žena" "žena" "žena" "žena" "žena" "žena" "muž" 
[101] "muž"  "žena" "žena" "žena" "muž"  "žena" "žena" "žena" "muž"  "žena"
[111] "žena" "žena" "muž"  "žena" "muž"  "žena" "muž"  "muž"  "muž"  "žena"
[121] "muž"  "muž"  "muž"  "muž"  "žena" "muž"  "muž"  "muž"  "muž"  "muž" 
[131] "muž"  "muž"  "muž"  "muž"  "muž"  "žena" "muž"  "muž"  "muž"  "muž" 
[141] "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž" 
[151] "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž" 
[161] "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "žena"
[171] "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž" 
[181] "žena" "muž"  "žena" "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž" 
[191] "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž"  "muž" 

Poté už jen stačí tento zápis vložit do length() a výsledkem se stává length(Katan$Pohlaví[!is.na(Katan$Pohlaví)]). Z tohoto důvodu je vám doufám nyní již jasné, proč nelze použít například funkci length(!is.na(Katan$Pohlaví)). S ní si užijete pouze error.

length(Katan$Pohlaví[!is.na(Katan$Pohlaví)])
[1] 199

Při tvorbě četnostních tabulek, pracujeme-li s numerickými proměnnými, může být výhodné takovouto proměnnou rozdělit do intervalů, čímž vytvoříme faktor. K tomu nám dobře poslouží příkaz cut(). Představte si například, že chceme rozdělit hráče podle následujících věkových kategorií (teenager do 18 let, dospělý od 18 do 26 let, dospělý od 26 do 65 let, důchodce od 65 let) a následně zjistit procentuální podíly těchto skupin.

AgeGroup <- cut(
    Katan$Věk, 
    breaks = c(0, 18, 26, 65, 150), 
    right = FALSE,
    labels = c("teenager do 18 let", "dospělý od 18 do 26 let", 
               "dospělý od 26 do 65 let", "důchodce od 65 let"))
# right = FALSE znamená, že v případě c(0, 18, 26, 65, 150) 
# intervaly nabývají hodnot <0, 18);  <18, 26); atd.

# right = TRUE znamená, že v případě c(0, 18, 26, 65, 150) 
# intervaly nabývají hodnot (0, 18>; (18, 26>; atd.
                                   
table(AgeGroup)/length(AgeGroup)
AgeGroup
     teenager do 18 let dospělý od 18 do 26 let dospělý od 26 do 65 let 
                  0.130                   0.425                   0.425 
     důchodce od 65 let 
                  0.020 

Osadníci z Katanu jsou vysoce populární zejména v nejmladší věkové kategorii. O tom svědčí ta skutečnost, že 55,5 % jedinců z naší databáze je mladší 26 let. Na druhou stranu je možné se setkat i s lidmi v důchodovém věku, kteří Osadníkům též propadli.

V příkazech summary() a table() nezůstanou stranou ani podmínky. Co takhle kupříkladu zjistit, kolik žen nad 25 let naše databáze Katan obsahuje?

summary(
    Katan$Pohlaví == "žena" & 
    Katan$věk > 25) 
# příkaz shrne výsledky do podoby TRUE a FALSE
   Mode   FALSE    TRUE 
logical     190      10 

Žen nalezneme v této kategorii pouze deset, na rozdíl od mužů, kterých tu je 79. Srovnáme-li tento výsledek s celkovými počty mužů a žen zvlášť, můžeme usoudit, že ženy po dosažení 26 let ztrácejí o Osadníky zájem. Zatímco muži nad 25 let tvoří přibližně 55 % veškerých mužských hráčů, mezi ženami je to pouhých 17 %.

Podmínky v R tvoříme za pomoci tzv. logických operátorů. Jedním z nich mohou být například dvě rovnítka. Ty použijeme tehdy, chceme-li R sdělit, že z určité proměnné chceme vybrat pouze určité hodnoty, v našem případě pouze ženy. Ampersand, další logický operátor (&), značí to, že se podmínka skládá z více částí, jež musí být současně splněny. Shrnutí logických operátorů můžete vidět v tabulce níže.

Znak         | Význam
--------------------------------
<            | méně než       
<=           | méně nebo rovno
>            | větší než
>=           | větší nebo rovno
==           | rovno
!=           | nerovno  
!x           | ne x
x & y        | x a y
x | y        | x nebo y

Stejného výsledku jako v předchozím skriptu můžeme opět dosáhnout i s pomocí příkazu table().

table(
    Katan$Pohlaví == "žena" & 
    Katan$Věk > 25)

FALSE  TRUE 
  190    10 

Abychom si vyzkoušeli další logické operátory, pokusme se nyní zjistit, kolik mužů v naší databázi pracuje a současně nemá žádné vysokoškolské vzdělání. Bude procento takovýchto jedinců vyšší než u vysokoškoláků?

table(
    Katan$Pohlaví == "muž" & 
    Katan$Práce == "pracuje" &
    (Katan$Vzdělání == "ZŠ" | Katan$Vzdělání == "SŠ"))

FALSE  TRUE 
  156    44 
table(
    Katan$Pohlaví == "muž" & 
    Katan$Práce == "pracuje" &
    (Katan$Vzdělání == "Bc - VŠ" | Katan$Vzdělání == "VŠ"))

FALSE  TRUE 
  159    41 

Bude. Dohromady se v naší databázi objevuje 85 pracujících mužů, z nichž necelých 52 % nemá vysokoškolské vzdělání. Osadníci z Katanu se proto u mužů těší stejné oblibě bez ohledu na vzdělání. A jak to vypadá u žen?

table(
    Katan$Pohlaví == "žena" & 
    Katan$Práce == "pracuje" &
    (Katan$Vzdělání == "ZŠ" | Katan$Vzdělání == "SŠ"))

FALSE  TRUE 
  196     4 
table(
    Katan$Pohlaví == "žena" & 
    Katan$Práce == "pracuje" &
    (Katan$Vzdělání == "Bc - VŠ" | Katan$Vzdělání == "VŠ"))

FALSE  TRUE 
  182    18 

U těch je situace odlišná. Pracujících žen tu máme celkem 22, z nichž pouze 4 nemají žádné vysokoškolské vzdělání.

Posledním logickým operátorem, který si zde ukážeme, se stane nerovno. S ním už jsme se ale částečně seznámili v rámci příkazu Katan$Pohlaví[!is.na(Katan$Pohlaví)]. Máte ve svém RStudiu stále nahraný soubor DirtyKatan s chybějícími hodnotami z předchozí lekce? Pokud ano, podívejme se na další příkaz. V něm budeme chtít zjistit, kolik máme v databázi žen, které vychovávají alespoň jedno dítě a nechybí jim hodnota v rámci proměnné Partie. Jak uvidíte, příliš mnoho jich tu mít nebudeme. Tyto ženy totiž povětšinou na Osadníky z Katanu čas nemají, a proto se také příliš neobjevují v naší databázi. Nevíte někdo, proč tomu tak je?

table(
    Katan$Pohlaví == "žena" & 
    Katan$Děti != 0 &
    !is.na(Katan$Partie))   

FALSE  TRUE 
  198     2 

Výsledky z příkazu table() můžeme následně jednoduše uložit do nově vzniklé proměnné. U příkazu summary() můžeme výsledek též uložit, na rozdíl od příkazu table() nám nicméně jeho formát neumožní následnou práci s takto vzniklou databází, proto se ve zbytku lekce zaměříme výhradně na table().

Tabulka <- table(
    Katan$Pohlaví == "žena" & 
    Katan$Děti != 0 &
    !is.na(Katan$Partie))

FALSE  TRUE 
  198     2 

Vyzkoušejme si nyní další variantu příkazu table(). V ní budeme chtít zjistit počty mužů a žen, kteří pracují a kteří nikoliv. Současně tak budeme vytvářet četnostní tabulku s celkově čtyřmi údaji.

Tabulka <- table(
    Katan$Práce, 
    Katan$Pohlaví)
           
            muž žena
  nepracuje  57   36
  pracuje    85   22

Co se však stane, použijeme-li v tuto chvíli příkaz View(Tabulka)? Uvidíme to samé jako v konzoli?

View(Tabulka)

Formát tabulky vypadá jinak než v konzoli, což v tomto případě nemusí být vždy úplně vhodné (ačkoliv ve většině případů bude, viz osmá kapitola Kalkata: Tidyr). Co v takovém případě dělat? Bude nutné využít následující příkaz as.data.frame.matrix().

Tabulka <- 
     as.data.frame.matrix(Tabulka)
          muž žena
nepracuje  57   36
pracuje    85   22

Nyní je již vše v pořádku. Přesvědčme se však.

Box: Boxplot

Ačkoliv bude grafům v R vyhrazena více než celá jedna kapitola, již nyní se podíváme, jak vytvořit zcela jednoduchý krabicový graf, ve kterém využijeme výše diskutovaný příkaz as.data.frame.matrix().

Náš úkol zní. V jaké věkové skupině (0 až 17, 18 až 40, 41 až 64, 65 a více) v rámci databáze Katan tvoří kuřáci největší podíl? Graficky znázorni.

Nejdříve musíme vytvořit novou proměnnou s názvem AgeGroup, která rozdělí osadníky a osadnice do čtyř věkových skupin.

AgeGroup <- cut(
    Katan$Věk, breaks = c(0, 17, 40, 64, 100), 
    right = TRUE, 
    labels = c("0 až 17", "18 až 40", "41 až 64", "65 a více"))
[1] 0 až 17 0 až 17 0 až 17 0 až 17 0 až 17 0 až 17
Levels: 0 až 17 18 až 40 41 až 64 65 a více

Poté vytvoříme nový soubor MoreData, který bude obsahovat i nově vytvořenou proměnnou AgeGroup. K tomu využijeme příkaz cbind(), který prozatím ještě neznáte a jež si blíže představíme v přespříští lekci.

MoreData <- cbind(Katan, AgeGroup)
  Partie Věk Pohlaví Vzdělání Kolej     Práce Kouření   Klub Děti AgeGroup
1      4  13    žena       ZŠ    ne nepracuje nekouří nečlen    0  0 až 17
2      4  13    žena       ZŠ    ne nepracuje nekouří nečlen    0  0 až 17
3      3  14     muž       ZŠ    ne nepracuje nekouří   člen    0  0 až 17
4      8  14     muž       ZŠ    ne nepracuje nekouří nečlen    0  0 až 17
5      5  15     muž       ZŠ    ne nepracuje nekouří   člen    0  0 až 17
6      6  15     muž       ZŠ    ne nepracuje nekouří   člen    0  0 až 17

Následně stvoříme proměnnou Table, která zobrazí počty kuřáků a nekuřáků v dané věkové kategorii.

Table <- table(MoreData$AgeGroup, MoreData$Kouření)

V této chvíli máme data připravena na příkaz as.data.frame.matrix(). Za ním bude následovat kód, pomocí kterého vytvoříme finální datovou tabulku s procenty (FinalData).

Table <- as.data.frame.matrix(Table)

FinalData <- cbind(
  Table$nekouří/(Table$nekouří + Table$kouří)*100,
  Table$kouří/(Table$nekouří + Table$kouří)*100)
         [,1]       [,2]
[1,] 92.30769   7.692308
[2,] 67.54967  32.450331
[3,] 57.89474  42.105263
[4,]  0.00000 100.000000

V této chvíli již máme vytvořenou závěrečnou tabulku, ze které bude vycházet náš sloupcový graf. Před tím nicméně bude nutné tabulku ještě transponovat, jelikož chceme mít vždy jeden sloupec pro danou věkovou kategorii.

FinalData <- t(FinalData)
          [,1]     [,2]     [,3] [,4]
[1,] 92.307692 67.54967 57.89474    0
[2,]  7.692308 32.45033 42.10526  100

Na úplný závěr vytvoříme samotný graf.

barplot(FinalData, 
# parametr col určuje barvy ve sloupcích, ty udáváme ve formátu HEX
        col = c("#323A85","#FFD900"), 
# names.arg určí popisky na x-ové ose
        names.arg = c("0 až 17 let", "18 až 40 let", 
                      "41 až 64 let", "65 let a více"), 
# las = 1 určí horizontální směr popisků na osách
        las = 1)

A takto vypadá pro rekapitulaci celý skript dohromady.

AgeGroup <- cut(
  Katan$Věk, breaks = c(0, 17, 40, 64, 100), 
  right = TRUE, 
  labels = c("0 až 17", "18 až 40", "41 až 64", "65 a více"))
MoreData <- cbind(Katan, AgeGroup)
Table <- table(MoreData$AgeGroup, MoreData$Kouření)
Table <- as.data.frame.matrix(Table)
FinalData <- cbind(
  Table$nekouří/(Table$nekouří + Table$kouří)*100,
  Table$kouří/(Table$nekouří + Table$kouří)*100)
FinalData <- t(FinalData)
barplot(FinalData, 
        col = c("#323A85","#FFD900"), 
        names.arg = c("0 až 17 let", "18 až 40 let", 
                      "41 až 64 let", "65 let a více"), 
        las = 1)

Pokračujme dalším příkazem funkce table(). V něm budeme chtít zjistit počty pracujících podle pohlaví, a to vše podle vzdělání. Oproti předchozímu příkazu tudíž vytvoříme četnostní tabulku rozdělenou podle hodnot ze tří proměnných.

Tabulka <- table(
    Katan$Práce, 
    Katan$Pohlaví, 
    Katan$Vzdělání)
, ,  = Bc - VŠ

           
            muž žena
  nepracuje   6    4
  pracuje     0    9

, ,  = SŠ

           
            muž žena
  nepracuje  31   19
  pracuje    39    4

, ,  = VŠ

           
            muž žena
  nepracuje   0    0
  pracuje    41    9

, ,  = ZŠ

           
            muž žena
  nepracuje  20   13
  pracuje     5    0

Ačkoliv v konzoli vypadá formát souboru Tabulka jako array (pole), přesto zjistíme, že tu stále pracujeme s datovou tabulkou, o čemž svědčí nejenom příkaz class(), ale i View().

Column

Příklady

Příklad 5

Zjistěte procento kuřáků a nekuřáků v databázi Katan.

Příklad 6

Zjistěte počet žen, které bydlí na koleji a mají děti.

Příklad 7

Zjistěte počet mužů a žen, kteří bydlí na koleji a kteří nikoliv.

Příklad 8

Zjistěte, zdali muži chodí procentuálně více do práce než ženy. Vytvořte přehlednou tabulku, která bude zobrazovat tyto sloupce:

  1. nepracuje (počet nepracujících mužů a žen);
  2. pracuje (počet pracujících mužů a žen);
  3. celkový počet (počet všech mužů a žen);
  4. nepracuje_procento (podíl nepracujících mužů a žen);
  5. pracuje_procento (podíl pracujících mužů a žen).

První řádek by měl charakterizovat muže, druhý ženy.

Příklad 9

Vytvořte četnostní tabulku mužů a žen podle jejich vzdělání a kouření.

Příklad 10

Vytvořte v rámci databáze Katan faktorovou proměnnou Rodič, která bude rozdělovat jedince do čtyř skupin podle proměnné Děti na bezdětný, rodič začátečník (jedno dítě), pokročilý rodič (dvě děti) a zasloužilý rodič (tři a více dětí). Následně zjistěte procentuální zastoupení těchto čtyř skupin.

Filtrace dat

Column

La Paz: Filtrace dat

Filtrace dat

Práce s daty obsahuje neustálou potřebu údaje různě třídit a filtrovat. Při tom dochází k tvorbě nejenom nových proměnných, ale i celých databází. Pojďme se proto podívat jak na ně. Začneme tím, že se seznámíme s tvorbu logických vektorů ve tvaru TRUE a FALSE.

Následující skript si klade za cíl vytvořit v konzoli vektor (bez vytvoření proměnné), který bude obsahovat tolik hodnot TRUE a FALSE jako databáze Katan. TRUE nastane pouze v případě, bude-li daný řádek databáze Katan obsahovat ženu od 15 do 20 let (včetně), u níž nechybí hodnota pro proměnnou Partie.

Katan$Pohlaví == "žena" & 
Katan$Věk >= 15 & 
Katan$Věk <= 20 &
!is.na(Katan$Partie)
  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE
 [13]  TRUE  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE
 [25]  TRUE FALSE FALSE FALSE  TRUE  TRUE FALSE  TRUE  TRUE FALSE  TRUE  TRUE
 [37]  TRUE FALSE FALSE  TRUE  TRUE  TRUE FALSE  TRUE FALSE  TRUE FALSE FALSE
 [49]  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [73] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [85] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [97] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[109] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[121] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[133] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[145] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[157] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[169] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[181] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[193] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE

Chceme-li předchozí vektor uložit, není nic jednoduššího než výsledek přiřadit proměnné s novým jménem, v našem případě FemData.

FemData <-  
  Katan$Pohlaví == "žena" & 
  Katan$Věk >= 15 &
  Katan$Věk <= 20
  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE
 [13]  TRUE  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE
 [25]  TRUE FALSE FALSE FALSE  TRUE  TRUE FALSE  TRUE  TRUE FALSE  TRUE  TRUE
 [37]  TRUE FALSE FALSE  TRUE  TRUE  TRUE FALSE  TRUE FALSE  TRUE FALSE FALSE
 [49]  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [73] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [85] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [97] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[109] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[121] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[133] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[145] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[157] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[169] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[181] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[193] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE

Je-li však naším cílem vytvořit novou databázi, která bude obsahovat pouze ty řádky, jež splňují výše uvedené parametry, bude nutné povolat do služby hranaté závorky. V následujícím příkazu si prosím všimněte čárky uvnitř závorky. Vzhledem k tomu, že budeme postupovat v naší selekci po řádcích, a nikoliv po sloupcích, budou podmínky uvedeny hned za závorkou a teprve až po nich bude následovat čárka. V případě, že za čárkou bude následovat konec závorky, znamená to, že v nové databázi FemData budeme chtít zachovat všechny sloupce z databáze Katan.

FemData2<- Katan[
  Katan$Pohlaví == "žena" & 
  Katan$Věk > 15 &
  Katan$Věk <= 20, ]  
# A tibble: 19 x 9
   Partie   Věk Pohlaví Vzdělání Kolej Práce     Kouření Klub    Děti
    <dbl> <dbl> <chr>   <chr>    <chr> <chr>     <chr>   <chr>  <dbl>
 1      3    16 žena    ZŠ       ne    nepracuje nekouří člen       0
 2      5    16 žena    ZŠ       ne    nepracuje nekouří nečlen     0
 3      4    16 žena    ZŠ       ne    nepracuje nekouří člen       0
 4      6    17 žena    ZŠ       ne    nepracuje nekouří člen       0
 5      7    17 žena    ZŠ       ne    nepracuje nekouří člen       0
 6      8    18 žena    SŠ       ano   nepracuje nekouří člen       0
 7      8    18 žena    ZŠ       ne    nepracuje nekouří člen       0
 8      5    18 žena    SŠ       ne    nepracuje nekouří nečlen     0
 9      3    18 žena    ZŠ       ne    nepracuje kouří   nečlen     0
10      2    19 žena    SŠ       ano   nepracuje nekouří nečlen     0
11      5    19 žena    SŠ       ne    nepracuje nekouří nečlen     0
12      2    19 žena    SŠ       ano   nepracuje nekouří nečlen     0
13      7    19 žena    SŠ       ano   nepracuje nekouří člen       0
14      6    19 žena    SŠ       ne    nepracuje nekouří člen       0
15      9    19 žena    ZŠ       ne    nepracuje kouří   nečlen     0
16      5    20 žena    SŠ       ano   nepracuje nekouří nečlen     0
17      8    20 žena    SŠ       ano   nepracuje nekouří nečlen     0
18      5    20 žena    SŠ       ne    nepracuje kouří   člen       0
19      3    20 žena    SŠ       ano   nepracuje kouří   člen       0

Pokud bychom nicméně chtěli zachovat pouze první sloupec (proměnnou Partie) a ostatní už nikoliv, vypadal by příkaz následovně.

FemData2<- Katan[
  Katan$Pohlaví == "žena" & 
  Katan$Věk > 15 &
  Katan$Věk <= 20, 1]  
# A tibble: 19 x 1
   Partie
    <dbl>
 1      3
 2      5
 3      4
 4      6
 5      7
 6      8
 7      8
 8      5
 9      3
10      2
11      5
12      2
13      7
14      6
15      9
16      5
17      8
18      5
19      3

Výše uvedený příkaz by bylo možné napsat ještě jedním způsobem. V něm už čárku uvnitř hranaté závorky nenalezneme, jelikož vybíráme pouze z jedné konkrétní proměnné (jednoho sloupce) a nikoliv z celé databáze.

FemData2 <-
    Katan$Partie[
    Katan$Pohlaví == "žena" & 
    Katan$Věk >= 15 &
    Katan$Věk <= 20]
 [1] 3 3 9 3 5 4 6 7 8 8 5 3 2 5 2 7 6 9 5 8 5 3

Filtrovat data samozřejmě nemusíme pouze kvůli tomu, abychom vytvořili novou proměnnou či databázi, ale třeba i za tím účelem, abychom například zjistili věkový průměr dívek, které pracují a mají přitom vysokoškolské vzdělání.

mean(Katan$Věk[
    Katan$Pohlaví == "žena" & 
    Katan$Práce == "pracuje" & 
    Katan$Vzdělání == "Bc-VŠ" | Katan$Vzdělání == "VŠ"])
[1] 31

A co muži? Jaký je jejich věkový průměr ve stejné kategorii?

mean(Katan$Věk[
    Katan$Pohlaví == "muž" & 
    Katan$Práce == "pracuje" & 
    Katan$Vzdělání == "Bc-VŠ" | Katan$Vzdělání == "VŠ"])
[1] 31

Vypadá to možná až neuvěřitelně, ale jejich věkový průměr je naprosto totožný jako u žen.

Třídění dat

Máte rádi, když jsou data v databázi hezky seřazena podle velikosti? Ukažme si nyní, jak lze seřadit naši databázi Katan podle proměnné Partie, následně dle Věku a v závěru podle Pohlaví od nejmenší po největší hodnoty (respektive dle abecedy).

Katan2 <- Katan[order(Katan$Partie, Katan$Věk, Katan$Pohlaví), ]
# pokud chceme od největší po nejmenší, použijeme parametr decreasing = TRUE
# A tibble: 200 x 9
   Partie   Věk Pohlaví Vzdělání Kolej Práce     Kouření Klub    Děti
    <dbl> <dbl> <chr>   <chr>    <chr> <chr>     <chr>   <chr>  <dbl>
 1      1    23 žena    SŠ       ano   nepracuje nekouří nečlen     1
 2      1    24 muž     SŠ       ne    nepracuje kouří   člen       0
 3      1    24 žena    Bc - VŠ  ne    pracuje   nekouří nečlen     0
 4      1    24 žena    VŠ       ne    pracuje   kouří   člen       0
 5      1    25 muž     VŠ       ne    pracuje   kouří   člen       0
 6      1    25 žena    Bc - VŠ  ne    pracuje   kouří   nečlen     0
 7      1    27 muž     VŠ       ne    pracuje   nekouří člen       1
 8      1    28 muž     VŠ       ne    pracuje   nekouří nečlen     1
 9      1    28 muž     VŠ       ne    pracuje   kouří   nečlen     0
10      1    28 žena    VŠ       ne    pracuje   nekouří nečlen     0
# ... with 190 more rows

Příkaz order() nicméně dokáže mnohem víc. Následující kód nám proto ukáže, kterak lze vytvořit vektor, který bude obsahovat jednotlivá pořadí (nikoliv samotné hodnoty) určité proměnné od nejmenší hodnoty po tu největší. Pro bližší názornost, první číslo ve vektoru Order nabývá hodnoty 90, protože v databázi Katan nalezneme nejnižší hodnotu proměnné Partie právě na 90. místě. V případě, že je stejných hodnot více, dostane přednost vždy ta nejdřívější.

Order <- order(Katan$Partie)
  [1]  90  92  95 106 108 119 124 126 130 134 136 137 139 140 142 143 144 145
 [19] 146 147 149 150 151 152 154 155 157 158 159 161 162 164 165 166 168 174
 [37] 175 176 177 178 179 180 181 182 183 185 186 191 193 194 195 196 198 200
 [55]  19  24  27  35  37  39  45  48  57  59  64  65  67  71  72  73  79  86
 [73]  98  99 100 103 110 114 116 120 121 127 128 129 131 132 133 135 138 141
 [91] 171 172 187 189 190 192 197 199   3   8   9  13  33  34  47  50  51  52
[109]  74  80  87  89  93  97 101 102 104 105 111 112 113 115 117 118 122 123
[127] 125 153 156 160 163 167 169 170 173 184 188   1   2  18  23  43  53  56
[145]  60  63  70  75  81  82  88  94  96 107 109 148   5  11  12  14  16  32
[163]  36  44  49  54  58  66  78  83   6   7  17  21  28  41  61  69  84  85
[181]  15  25  26  40  55  62  68  77  91   4  20  29  30  31  38  46  76  10
[199]  22  42

Poslední příkaz, který si tu v této lekci ukážeme, se nazývá sort(). Ten na rozdíl od order() vytvoří vektor se samotnými hodnotami seřazenými od těch nejmenších po největší.

Sort <- sort(Katan$Partie)
# pokud chceme hodnoty v opačném pořadí, použijeme funkci decreasing = TRUE
  [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 [38] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 [75] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3
[112] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4
[149] 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7
[186] 7 7 7 7 8 8 8 8 8 8 8 8 9 9 9

Column

Příklady

Příklad 11

Vytvořte logický vektor, kde TRUE značí muže do 25 let, který odehraje za měsíc alespoň 5 partií deskové hry Osadníci z Katanu.

Příklad 12

Vytvořte novou databázi Katan2, která bude obsahovat pouze ženy do 25 let, které kouří a odehrají alespoň 3 partie deskové hry Osadníci z Katanu. Výslednou databázi seřaďte podle Věku od nejstarší slečny po nejmladší.

Kombinace dat

Column

Buenos Aires: Kombinace dat

V rámci R se budeme nezřídka kdy setkávat s potřebou propojování (a odstraňování) proměnných v data frame. Jak na to se naučíme právě nyní v Buenos Aires. Začneme tím, že si vytvoříme logický vektor, který bude obsahovat TRUE pro muže, kteří chodí do práce. Naším následujícím úkolem bude tento vektor připojit ke stávající databázi Katan. K tomu využijeme příkaz cbind() (c označuje sloupec - column).

MenWork <-  
  Katan$Pohlaví == "muž" & 
  Katan$Práce == "pracuje"
  MoreData <- cbind(Katan, MenWork)
  Partie Věk Pohlaví Vzdělání Kolej     Práce Kouření   Klub Děti MenWork
1      4  13    žena       ZŠ    ne nepracuje nekouří nečlen    0   FALSE
2      4  13    žena       ZŠ    ne nepracuje nekouří nečlen    0   FALSE
3      3  14     muž       ZŠ    ne nepracuje nekouří   člen    0   FALSE
4      8  14     muž       ZŠ    ne nepracuje nekouří nečlen    0   FALSE
5      5  15     muž       ZŠ    ne nepracuje nekouří   člen    0   FALSE
6      6  15     muž       ZŠ    ne nepracuje nekouří   člen    0   FALSE

Výše uvedené dva příkazy (tvorbu vektoru a následné použití příkazu cbind()) lze provést dokonce i dohromady.

MoreData2 <- cbind(
  Katan,
    MenWork =  
    Katan$Pohlaví == "muž" & 
    Katan$Práce == "pracuje")

Na druhou stranu zde existuje ještě jeden mnohem triviálnější příkaz než cbind(). Vezměme si do úvahy opět vektor MenWork, který stojí mimo databázi Katan. Pro jeho přidání ke Katanu lze využít i následující styl zápisu.

Katan$MenWork <- MenWork

Takovýto formát velice elegantně přidá vektor MenWork jako další proměnnou databáze Katan (na pozici posledního sloupce).

Kromě příkazu cbind() nesmíme zapomenout ani na paste(). Ten na rozdíl od cbind() spojuje stávající vektory či sloupce data frame přímo do sebe, a vytváří tak zcela nový vektor hodnot.

AgeGender <- paste(
    Katan$Věk, 
    Katan$Pohlaví)
[1] "13 žena" "13 žena" "14 muž"  "14 muž"  "15 muž"  "15 muž" 

Chceme-li mezi proměnné vložit určitý znak, např. podtržítko, využijeme parametr s názvem sep.

AgeGender <- paste(
    Katan$Věk, 
    Katan$Pohlaví,
    sep = "_")
[1] "13_žena" "13_žena" "14_muž"  "14_muž"  "15_muž"  "15_muž" 

Příkazy paste() a cbind() lze opět zkombinovat v jeden příkaz.

Katan2 <- cbind(
    Katan,
    AgeGender = paste(
        Katan$Věk, 
        Katan$Pohlaví))
  Partie Věk Pohlaví Vzdělání Kolej     Práce Kouření   Klub Děti AgeGender
1      4  13    žena       ZŠ    ne nepracuje nekouří nečlen    0   13 žena
2      4  13    žena       ZŠ    ne nepracuje nekouří nečlen    0   13 žena
3      3  14     muž       ZŠ    ne nepracuje nekouří   člen    0    14 muž
4      8  14     muž       ZŠ    ne nepracuje nekouří nečlen    0    14 muž
5      5  15     muž       ZŠ    ne nepracuje nekouří   člen    0    15 muž
6      6  15     muž       ZŠ    ne nepracuje nekouří   člen    0    15 muž

Bratrem příkazu cbind() je rbind(), který spojuje databáze po řádcích. Jeho praktické využití může být například v tom, máme-li za cíl připojit ke stávající databázi nové řádky, například nově získaná data od dalších respondentů. Vytvořme si proto novou databázi KatanNEW, která bude obsahovat dvě pozorování pro všech devět proměnných databáze Katan. Tu následně připojíme ke stávající databázi Katan.

KatanNEW <- data.frame(
  Partie = c(2, 3),
  Věk = c(20, 30),
  Pohlaví = c("muž", "muž"),
  Vzdělání = c("SŠ", "SŠ"),
  Kolej = c("ne", "ne"),
  Práce = c("pracuje", "pracuje"),
  Děti = c(0, 1),
  Kouření = c("nekouří", "nekouří"),
  Klub = c("nečlen", "nečlen"))

Katan <- rbind(Katan, KatanNEW)
tail(Katan)
# A tibble: 6 x 9
  Partie   Věk Pohlaví Vzdělání Kolej Práce   Kouření Klub    Děti
   <dbl> <dbl> <chr>   <chr>    <chr> <chr>   <chr>   <chr>  <dbl>
1      2    68 muž     ZŠ       ne    pracuje kouří   nečlen     4
2      1    69 muž     ZŠ       ne    pracuje kouří   nečlen     4
3      2    74 muž     ZŠ       ne    pracuje kouří   nečlen     2
4      1    75 muž     ZŠ       ne    pracuje kouří   nečlen     2
5      2    20 muž     SŠ       ne    pracuje nekouří nečlen     0
6      3    30 muž     SŠ       ne    pracuje nekouří nečlen     1

Použili jste někdy v Excelu příkaz svyhledat? Představte si, že máte dvě databáze, které chcete vzájemně propojit. První tabulka například obsahuje jméno, příjmení studenta a jeho identifikační číslo UČO. Ta druhá zahrnuje známky z matematiky, dějepisu a též UČO, které je pojítkem obou databází. Vaším cílem je spojit tyto databáze do jedné, jež bude obsahovat celkem pět sloupců (jméno, příjmení, UČO, matematika a dějepis).

data1 <- 
  data.frame(
    UČO = c(39, 45, 50, 60, 70, 
            89, 40, 65, 44, 77),
    jméno = c("Petr", "Ondřej", "Jana", "Eva", "David", 
              "Alois", "Filip", "Magda", "Bára", "Jakub"),
    příjmení = c("Novák", "Dvořák", "Nováková", "Dvořáková", "Svoboda", 
                 "Novotný", "Černý", "Svobodová", "Procházková", "Kučera")) 

data2 <- 
  data.frame(
    UČO = c(45, 39, 77, 60, 70, 
            89, 65, 40, 44, 50),
    matematika = c(1, 2, 2, 3, 4, 
                   5, 3, 1, 2, 2),
    dějepis = c(2, 1, 2, 4, 1, 
                5, 1, 1, 3, 1)) 

MergeData <-
  merge(data1, data2[ , c("UČO", "matematika", "dějepis")], by = "UČO")
   UČO  jméno    příjmení
1   39   Petr       Novák
2   45 Ondřej      Dvořák
3   50   Jana    Nováková
4   60    Eva   Dvořáková
5   70  David     Svoboda
6   89  Alois     Novotný
7   40  Filip       Černý
8   65  Magda   Svobodová
9   44   Bára Procházková
10  77  Jakub      Kučera
   UČO matematika dějepis
1   45          1       2
2   39          2       1
3   77          2       2
4   60          3       4
5   70          4       1
6   89          5       5
7   65          3       1
8   40          1       1
9   44          2       3
10  50          2       1
   UČO  jméno    příjmení matematika dějepis
1   39   Petr       Novák          2       1
2   40  Filip       Černý          1       1
3   44   Bára Procházková          2       3
4   45 Ondřej      Dvořák          1       2
5   50   Jana    Nováková          2       1
6   60    Eva   Dvořáková          3       4
7   65  Magda   Svobodová          3       1
8   70  David     Svoboda          4       1
9   77  Jakub      Kučera          2       2
10  89  Alois     Novotný          5       5

K souboru data1, který obsahuje údaje o jméně, příjmení a UČu, byla přiřazena databáze data2 se sloupci matematika a dějepis. Sloupec UČO znovu přiřazen nebude a zůstane v nové databázi MergeData pouze jednou. Pozor však na to, aby v obou souborech byl název proměnné, vzhledem ke které dojde ke spojení, stejný, a to včetně velikosti písmen.

Přidávat nové proměnné do data frame umíme. Co ale opačný případ? Vzpomenete si na jednu z možností odebrání proměnné, se kterou jsme se seznámili již v předchozí kapitole?

LessData <- Katan[ ,-(6)]
# A tibble: 6 x 8
  Partie   Věk Pohlaví Vzdělání Kolej Kouření Klub    Děti
   <dbl> <dbl> <chr>   <chr>    <chr> <chr>   <chr>  <dbl>
1      4    13 žena    ZŠ       ne    nekouří nečlen     0
2      4    13 žena    ZŠ       ne    nekouří nečlen     0
3      3    14 muž     ZŠ       ne    nekouří člen       0
4      8    14 muž     ZŠ       ne    nekouří nečlen     0
5      5    15 muž     ZŠ       ne    nekouří člen       0
6      6    15 muž     ZŠ       ne    nekouří člen       0

Následující příkaz už ale jistě neznáte. V něm totiž nebudeme využívat pořadí proměnné v databázi, ale jejího názvu.

Katan$Práce <- NULL
# A tibble: 6 x 8
  Partie   Věk Pohlaví Vzdělání Kolej Kouření Klub    Děti
   <dbl> <dbl> <chr>   <chr>    <chr> <chr>   <chr>  <dbl>
1      4    13 žena    ZŠ       ne    nekouří nečlen     0
2      4    13 žena    ZŠ       ne    nekouří nečlen     0
3      3    14 muž     ZŠ       ne    nekouří člen       0
4      8    14 muž     ZŠ       ne    nekouří nečlen     0
5      5    15 muž     ZŠ       ne    nekouří člen       0
6      6    15 muž     ZŠ       ne    nekouří člen       0

Column

Příklady

Příklad 13

Vytvořte proměnnou s názvem Pohlaví_Vzdělání, která v sobě bude obsahovat údaje z obou těchto proměnných. Tuto proměnnou následně připojte k databázi Katan.

Příklad 14

Výše uvedenou proměnnou Pohlaví_Vzdělání odstraňte z databáze Katan2.

Příklad 15

Vytvořte Databázi A, která obsahuje dvě proměnné. Tou první bude proměnná ID, jež obsahuje čísla od jedné do 30 (náhodně uspořádaná, na příkaz 1:30 tudíž zapomeňte). Tou druhou proměnnou bude zeměpis, která obsahuje náhodný vektor známek z písemky. Následně vytvořte obdobnou Databázi B, která bude naopak obsahovat známky z matematiky. Vaším úkolem bude tyto dvě databáze spojit podle proměnné ID. A aby to nebylo tak jednoduché, známky z jednotlivých předmětů se budou vyskytovat s následující pravděpodobností (1: 30 %; 2: 50 %; 3: 10 %; 4: 5 %; 5: 5 %). Jak je vidět, pan učitel byl velice mírný.

Rodina apply

Column

Rio de Janeiro: Rodina apply

Společnou vlastností příkazů apply() a tapply() je schopnost aplikovat funkci na vybrané části datového souboru bez použití cyklu, což má výhody v přehlednosti i rychlosti výpočtu. Co se však za touto tajuplnou větou skrývá? Odpověď nenalezneme v temných zákoutích Ria, ale v této lekci. Stejně jako v těch předchozích, i nyní bude nejrychlejší si vše ukázat na konkrétních příkladech. Nejdříve si však vytvořme vzorovou matici, kterou použijeme na ukázku příkazu apply(), který se pojí právě s maticemi.

# vzorová matice
matice <- matrix(c(1:9), nrow = 3, byrow = TRUE)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8    9

Naším prvním úkolem bude vypočítat průměry ve všech sloupcích matice s názvem matice.

apply(matice, MARGIN = 2, FUN = mean)   
# margin = 1 znamená počítání po řádcích
# příkaz lze zapsat i jako apply(matice, 2, mean)
[1] 4 5 6

Nechceme-li počítat průměry ve všech sloupcích, ale třeba pouze v prvních dvou, použijeme staré dobré hranaté závorky.

apply(matice[ ,1:2], MARGIN = 2, FUN = mean)    
[1] 4 5

I v matici se nám občas může stát, že nám budou chybět některá data. Pro takový případ tu máme připraven parametr na.rm = TRUE, se kterým jsme se již v této kapitole seznámili (viz Statistika 0).

apply(matice, MARGIN = 2, FUN = mean, na.rm = TRUE) 
[1] 4 5 6

V rodině funkcí apply() nalezneme i další sourozence. Jedná se například o funkce sapply(), vapply(), lapply() či mapply(). My se však seznámíme pouze s tapply(), který na rozdíl od předchozích příkazů bude mít nejpraktičtější využití, jelikož ho využijeme v rámci data frame. Představte si například, že chcete vypočítat průměr u proměnné Věk. Žádný problém. Co když ale následně budete chtít vypočítat průměr zvlášť u mužů a žen? A co když budete chtít zajít ještě dál a vaším cílem bude zjistit věkový průměr nejenom podle pohlaví, ale i podle toho, zdali jedinci chodí do práce či nikoliv? Bude se vám chtít neustále vypisovat nové a nové řádky skriptu pro mean() nebo byste raději napsali jeden jednoduchý příkaz? V případě, že preferujete druhou možnost, je funkce tapply() pro vás jako stvořena. Podívejme se, jak lze výše diskutovaný příklad jednoduše vyřešit. Začneme tím, že vypočítáme věkové průměry podle pohlaví.

tapply(
    Katan$Věk, 
    Katan$Pohlaví, 
    FUN = mean, 
    simplify = TRUE, 
    na.rm = TRUE)   
# příkaz simplify zjednoduší formát zobrazení výsledku
# na.rm = TRUE využijeme tehdy, pokud máme v datech chybějící hodnoty 
     muž     žena 
29.81690 22.31034 

Průměrný věk mužů v našem souboru dat je o více než sedm let vyšší než u žen. To je dáno zejména tím, že muži na rozdíl od žen nepřestávají hrát Osadníky z Katanu ani po dosažení 26 let (viz table a summary). Zkusme nyní tento výrok dokázat pomocí tapply(). K tomu budeme potřebovat napsat skript, který nám vypočítá průměrný věk podle pohlaví pro jedince, kteří ještě nedosáhli 26 let.

# Nejdříve vytvoříme vyfiltrovanou databázi Katan25 a poté 
# použijeme samotný příkaz tapply().
Katan25 <- Katan[Katan$Věk < 26, ]  
tapply(
    Katan25$Věk, 
    Katan25$Pohlaví,
    FUN = mean, 
    simplify = TRUE)

# podmínku lze vtělit i přímo do tapply() (viz další text)
tapply(
  Katan$Věk,
  list(Katan$Pohlaví, 
       Katan$Věk < 26),
  FUN = mean, 
  simplify = TRUE)
     muž     žena 
20.23810 20.52083 
       FALSE     TRUE
muž  37.4557 20.23810
žena 30.9000 20.52083

Zde naopak vidíme, že ve věkové skupině do 26 let je průměrný věk žen dokonce o několik měsíců vyšší. Předchozí výrok byl tudíž pravdivý.

V případě, že chceme výsledky rozdělit nejenom podle jedné, ale i více proměnných (nyní podle proměnné Pohlaví a Práce), použijeme datovou strukturu list. V rámci takového listu lze využít i podmínek (viz předchozí skript).

tapply(
    Katan$Věk,
    list(Katan$Pohlaví, 
         Katan$Práce),
    FUN = mean, 
    simplify = TRUE)
     nepracuje  pracuje
muž   19.80702 36.52941
žena  19.13889 27.50000

Výsledky výše uvedeného příkazu opět potvrzují naše dřívější zjištění. Ženy na rozdíl od mužů nemají na Osadníky z Katanu čas.

Nevlastním bratrem příkazu tapply() je funkce aggregate(). Ta je navržena tak, aby pracovala na více sloupcích s jednou funkcí a vrátila nám data frame s jedním řádkem pro každou kategorii. Zatímco funkce tapply() je navržena tím způsobem, aby fungovala na jediném vektoru s výsledky vrácenými jako matice nebo pole.

Takto bych to též nepochopil (dovolil jsem si použít větu z nejmenované učebnice), proto nezoufejme a podívejme se na následující příkazy. V prvním z nich se podobně jako u tapply() podíváme na to, jaké jsou věkové průměry našich osadníků podle pohlaví, kouření a jejich pracovního nasazení.

aggregate(Katan$Věk,
    list(Katan$Pohlaví,
         Katan$Kouření,
         Katan$Práce),
    FUN = mean, 
    simplify = TRUE,
    na.rm = TRUE)
# Příkaz funguje obdobně jako funkce tapply(), pouze vše 
# agreguje do přehledné tabulky data frame (na rozdíl 
# od tapply()). Výhodné zvlášť v případě, pokud máme v 
# příkazu více položek, podle kterých se objekt (Věk) 
# třídí (Pohlaví, Kouření, Práce).
  Group.1 Group.2   Group.3        x
1     muž   kouří nepracuje 21.16667
2    žena   kouří nepracuje 20.85714
3     muž nekouří nepracuje 19.44444
4    žena nekouří nepracuje 18.72414
5     muž   kouří   pracuje 39.85714
6    žena   kouří   pracuje 26.44444
7     muž nekouří   pracuje 34.20000
8    žena nekouří   pracuje 28.23077

V příkazu aggregate() lze využít podmínek stejně jako u tapply(). Oproti předchozímu skriptu však budeme chtít, aby naše věkové průměry byly roztříděny i podle toho, zdali je náš osadník z databáze Katan hrdým otcem či matkou (a je mu zákonných 18 let!).

aggregate(
    Katan$Věk,
    list(Katan$Pohlaví, 
      Katan$Kouření, 
      Katan$Práce, 
      Katan$Věk >= 18 &
        Katan$Děti >= 1),
    FUN = mean, 
    simplify = TRUE, 
    na.rm = TRUE)
   Group.1 Group.2   Group.3 Group.4        x
1      muž   kouří nepracuje   FALSE 21.16667
2     žena   kouří nepracuje   FALSE 20.85714
3      muž nekouří nepracuje   FALSE 19.44444
4     žena nekouří nepracuje   FALSE 18.57143
5      muž   kouří   pracuje   FALSE 26.25000
6     žena   kouří   pracuje   FALSE 25.12500
7      muž nekouří   pracuje   FALSE 28.28571
8     žena nekouří   pracuje   FALSE 28.23077
9     žena nekouří nepracuje    TRUE 23.00000
10     muž   kouří   pracuje    TRUE 43.88889
11    žena   kouří   pracuje    TRUE 37.00000
12     muž nekouří   pracuje    TRUE 35.16279

Nejstaršího věkového průměru dosahují pracující muži kuřáci a otcové od rodin, zatímco nejmladší jsou bezdětné nepracující ženy nekuřačky. Pro většinu z nás nejspíš žádné významné překvapení.

Column

Příklady

Příklad 16

Vypočítejte průměr proměnné Partie podle pohlaví a vzdělání.

Příklad 17

Vypočítejte medián proměnné Věk podle pohlaví a kouření.

Příklad 18

Vypočítejte průměr proměnné Partie podle pohlaví a vzdělání u jedinců, kteří mají alespoň jedno dítě.

Funkce

Column

Fortaleza: Funkce

Nenašli jste prozatím funkci, kterou jste hledali? Napište si ji sami. Stačí si prostudovat několik následujících odstavců, které tu jsou pro vás připraveny ve Fortaleze, o níž jste nejspíš nikdy neslyšeli, navzdory tomu, že patří mezi sto největších měst na světě.

Pamatujete si ze školy, jak se počítá obsah a obvod kruhu? Určitě, i když nezastírejte, že jste chvíli museli přemýšlet nebo v horším případě googlit. A pokud už jste v tom, podívejte na následující video, v němž možná konečně pochopíte, kde se tu ty vzorečky vlastně vzaly. My však přemýšlení nemáme příliš v oblibě, proto si napíšeme následující skript, který bude po zadání poloměru vše počítat za nás.

kruh <- function(r) {
    obvod <- 2*pi*r
    obsah <- pi*r^2
    return(c("Obvod kruhu" = obvod, "Obsah kruhu" = obsah))
}
kruh(4) 
Obvod kruhu Obsah kruhu 
   25.13274    50.26548 

Naše funkce se jmenuje zcela stylově kruh. Jelikož se ale jedná o funkci novou, kterou R prozatím nezná, musíme uvést příkaz function() a do závorky jeho parametr, jenž v našem případě bude značit poloměr r. Následuje složená závorka, do které zapíšeme samotné příkazy nové funkce kruh. Tím prvním bude vzoreček pro výpočet obsahu a tím druhým pro výpočet obvodu. Každá funkce musí mít svůj výstup, proto ještě do složené závorky nezapomeneme zapsat příkaz return() podle výše uvedeného vzoru. Závorku uzavřeme a příkaz vyzkoušíme. Funguje. Ale co když nechceme vypočítat obvod a obsah pouze pro jeden údaj poloměru, ale třeba pro celý dlouhý vektor poloměrů? Vyzkoušejme.

x <- 1:4    # vektor poloměrů
kruh(x)
Obvod kruhu1 Obvod kruhu2 Obvod kruhu3 Obvod kruhu4 Obsah kruhu1 Obsah kruhu2 
    6.283185    12.566371    18.849556    25.132741     3.141593    12.566371 
Obsah kruhu3 Obsah kruhu4 
   28.274334    50.265482 

Výsledek tu sice máme, výstup nicméně nevypadá příliš reprezentativně. Co s tím? Místo příkazu c() zkusíme do příkazu return(c(Obvod = obvod, Obsah = obsah)) vepsat list či ještě lépe data.frame.

# list
kruh <- function(r) {
    obvod <- 2*pi*r
    obsah <- pi*r^2
    return(list("Obvod kruhu" = obvod, "Obsah kruhu" = obsah))
}
x <- 1:4
kruh(x)

# data.frame
kruh <- function(r) {
    obvod <- 2*pi*r
    obsah <- pi*r^2
    return(data.frame("Obvod kruhu" = obvod, "Obsah kruhu" = obsah))
}
x <- 1:4
kruh(x)
[1] "List"
$`Obvod kruhu`
[1]  6.283185 12.566371 18.849556 25.132741

$`Obsah kruhu`
[1]  3.141593 12.566371 28.274334 50.265482
[1] "Data frame"
  Obvod.kruhu Obsah.kruhu
1    6.283185    3.141593
2   12.566371   12.566371
3   18.849556   28.274334
4   25.132741   50.265482

Tento výstup vypadá již o poznání lépe. Nezapomeňme ho proto uložit do naší nové proměnné KRUH. A aby bylo vše tak jak má být, doplníme datovou tabulku o sloupec s hodnotami poloměrů a ten přesuneme na první pozici.

KRUH <- kruh(x)
KRUH <- cbind(KRUH, x)
# nyní ještě přejmenujeme proměnnou x na Poloměr
colnames(KRUH)[3] <- "Poloměr"
# a tu přesuneme na první místo v data frame
KRUH <- KRUH[ , c(3, 1, 2)]
  Poloměr Obvod.kruhu Obsah.kruhu
1       1    6.283185    3.141593
2       2   12.566371   12.566371
3       3   18.849556   28.274334
4       4   25.132741   50.265482

Na závěr se ještě podívejme do pravého horního panelu, kde nám k sekci values a data nově přibyla sekce functions s naší nově vytvořenou funkcí kruh. Z toho nepřímo vyplývá, že naše funkce bude v R fungovat pouze v rámci právě otevřené relace RStudia. Po jejím ukončení funkce z R zmizí. Uložit ji nicméně lze velice jednoduše jako skript.

Column

Příklady

Příklad 19

Vytáhněte si rukávy, je tu pro vás připraven jeden docela komplikovaný příklad. Vaším úkolem bude vytvořit funkci s názvem mzdová_kalkulačka. Ta po udání hrubé mzdy vypočítá náklady zaměstnance na sociální pojištění, zdravotní pojištění a daň z příjmů fyzických osob.

Následně vytvořte tři náhodné vektory o sto položkách hodnot, které budou obsahovat údaje o hrubé mzdě, počtu dětí a manželce (nebo manželovi), jejíž (jehož) příjem je nižší než 68 000 Kč za rok (1: ano, 0: ne). Poté pomocí funkce mzdová_kalkulačka vypočítejte výše uvedená pojištění a daň z příjmů. Závěrem vytvořte data frame, který bude obsahovat sedm sloupců: hrubá mzda, čistá mzda, počet dětí, manžel(ka), sociální pojištění, zdravotní pojištění a daň z příjmů.

Pozn. sociální pojištění: 6,5 % z hrubé mzdy; zdravotní pojištění: 4,5 % z hrubé mzdy; daň z příjmů: 15 % ze superhrubé mzdy; superhrubá mzda: hrubá mzda * 1,34; daňová sleva na každého poplatníka: 2 070 Kč; daňová sleva na manžela(ku): 2 070 Kč; daňová sleva na dítě: 1. dítě = 1 267 Kč měsíčně, 2. dítě = 1 617 Kč, 3. a každé další dítě = 2 017 Kč.

Pro zjednodušení uvažujte, že sleva na dítě činí 1 500 Kč na všechny děti. Dosud jsme totiž neprobírali podmínku IF, bez jejíž pomoci byste tento problém nemohli vyřešit. Ta se stane předmětem našeho zájmu v příští kapitole.

V příkladu se nezapomeňte vypořádat s tím, že sleva na poplatníka a manželku může snížit daň maximálně na nulu, zatímco slevy na dítě se mohou přetvořit v tzv. daňový bonus, tj. daň může být záporná. Uveďme si příklad. Daň z příjmů byla u jedince, jenž má nárok na slevu na manželku, vypočítána na hodnotu 3 000 Kč. Sleva na poplatníka a manželku činí dohromady 4 140 Kč. Daň však nemůže jít do záporných hodnot, proto bude činit nula. V případě, že ale takový člověk měl například dvě děti, bude mu vypočítán daňový bonus ve výši 2 884 Kč (respektive v našem příkladu 3 000 Kč).

Příklady

Column

Column

Příklady: řešení

Příklad 1

Vypočítejte průměr proměnné Partie z databáze Katan. Uvažujte případ, že máte v databázi chybějící údaje.

mean(Katan$Partie, na.rm = TRUE)
[1] 3.095

Příklad 2

Vypočítejte minimum a maximum proměnné Partie.

range(Katan$Partie)
[1] 1 9

Příklad 3

Vypočítejte korelační koeficient mezi proměnnými Věk a Děti.

cor(
  Katan$Věk, 
  Katan$Děti, 
  use = "complete.obs") 
[1] 0.7961328

Příklad 4

Vypočítejte body mass index (hmotnost v kg/výška v m umocněná na druhou) pro následující databázi BMI. Výsledný vektor připojte ke stávající databázi BMI.

BMI <- data.frame(
  Hmotnost = c(60, 50, 49, 80, 90, 48, 63, 53, 75, 81),
  Výška = c(170, 166, 155, 190, 178, 158, 168, 163, 170, 185))
bmi <- BMI$Hmotnost/((BMI$Výška/100)^2)
BMI$bmi <- BMI 
   Hmotnost Výška      bmi
1        60   170 20.76125
2        50   166 18.14487
3        49   155 20.39542
4        80   190 22.16066
5        90   178 28.40550
6        48   158 19.22769
7        63   168 22.32143
8        53   163 19.94806
9        75   170 25.95156
10       81   185 23.66691

Příklad 5

Zjistěte procento kuřáků a nekuřáků v databázi Katan.

table(Katan$Smoke)/length(Katan$Smoke)

  kouří nekouří 
  0.315   0.685 

Příklad 6

Zjistěte počet žen, které bydlí na koleji a mají děti.

table(
  Katan$Pohlaví == "žena" &
  Katan$Kolej == "ano" &
  Katan$Děti != 0)

FALSE  TRUE 
  199     1 

Příklad 7

Zjistěte počet mužů a žen, kteří bydlí na koleji a kteří nikoliv.

table(Katan$Pohlaví, Katan$Kolej)
      
       ano  ne
  muž   18 124
  žena  16  42

Příklad 8

Zjistěte, zdali muži chodí procentuálně více do práce než ženy. Vytvořte přehlednou tabulku, která bude zobrazovat tyto sloupce:

  1. nepracuje (počet nepracujících mužů a žen);
  2. pracuje (počet pracujících mužů a žen);
  3. celkový počet (počet všech mužů a žen);
  4. nepracuje_procento (podíl nepracujících mužů a žen);
  5. pracuje_procento (podíl pracujících mužů a žen).

První řádek by měl charakterizovat muže, druhý ženy.

TABULKA <- as.data.frame.matrix(table(Katan$Pohlaví, Katan$Práce))
TABULKA$počet <- TABULKA$pracuje + TABULKA$nepracuje
TABULKA$nepracuje_procento <- round((TABULKA$nepracuje/TABULKA$počet)*100)
TABULKA$pracuje_procento <- round((TABULKA$pracuje/TABULKA$počet)*100)
     nepracuje pracuje počet nepracuje_procento pracuje_procento
muž         57      85   142                 40               60
žena        36      22    58                 62               38

Příklad 9

Vytvořte četnostní tabulku mužů a žen podle jejich vzdělání a kouření.

TABULKA <- table(
    Katan$Pohlaví, 
    Katan$Vzdělání, 
    Katan$Kouření)
, ,  = kouří

      
       Bc - VŠ SŠ VŠ ZŠ
  muž        2 25 13  7
  žena       6  3  5  2

, ,  = nekouří

      
       Bc - VŠ SŠ VŠ ZŠ
  muž        4 45 28 18
  žena       7 20  4 11

Příklad 10

Vytvořte v rámci databáze Katan faktorovou proměnnou Rodič, která bude rozdělovat jedince do čtyř skupin podle proměnné Děti na bezdětný, rodič začátečník (jedno dítě), pokročilý rodič (dvě děti) a zasloužilý rodič (tři a více dětí). Následně zjistěte procentuální zastoupení těchto čtyř skupin.

Rodič <- cut(
    Katan$Děti, 
    breaks = c(0, 1, 2, 10), 
    right = FALSE,
    labels = c("bezdětný", "rodič začátečník", 
               "pokročilý rodič", "zasloužilý rodič"))

table(Rodič)/length(Rodič)
Rodič
        bezdětný rodič začátečník  pokročilý rodič zasloužilý rodič 
            0.64             0.15             0.14             0.07 

Příklad 11

Vytvořte logický vektor, kde TRUE značí muže do 25 let (včetně), který odehraje za měsíc alespoň 5 partií deskové hry Osadníci z Katanu.

muži <-  
  Katan$Pohlaví == "muž" & 
  Katan$Věk <= 25 &
  Katan$Partie >= 5
  [1] FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE  TRUE  TRUE
 [13] FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE
 [25] FALSE  TRUE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE
 [37] FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [49] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE  TRUE FALSE FALSE
 [61] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE
 [73] FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE
 [85]  TRUE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE
 [97] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[109] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[121] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[133] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[145] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[157] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[169] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[181] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[193] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE

Příklad 12

Vytvořte novou databázi Katan2, která bude obsahovat pouze ženy do 25 let, které kouří a odehrají alespoň 3 partie deskové hry Osadníci z Katanu. Výslednou databázi seřaďte podle Věku od nejstarší slečny po nejmladší.

Katan2<- Katan[
  Katan$Pohlaví == "žena" & 
  Katan$Věk <= 25 &
  Katan$Kouření == "ano" &
  Katan$Partie >= 3, ]
Katan2 <- Katan2[order(Katan$Věk, decreasing=TRUE), ]
# A tibble: 11 x 9
   Partie   Věk Pohlaví Vzdělání Kolej Práce     Kouření Klub    Děti
    <dbl> <dbl> <chr>   <chr>    <chr> <chr>     <chr>   <chr>  <dbl>
 1      3    25 žena    VŠ       ne    pracuje   kouří   člen       0
 2      3    25 žena    Bc - VŠ  ne    pracuje   kouří   člen       0
 3      4    25 žena    VŠ       ne    pracuje   kouří   člen       0
 4      4    25 žena    Bc - VŠ  ano   nepracuje kouří   nečlen     0
 5      4    24 žena    Bc - VŠ  ano   pracuje   kouří   nečlen     0
 6      4    23 žena    Bc - VŠ  ano   nepracuje kouří   nečlen     0
 7      7    21 žena    SŠ       ano   nepracuje kouří   člen       0
 8      5    20 žena    SŠ       ne    nepracuje kouří   člen       0
 9      3    20 žena    SŠ       ano   nepracuje kouří   člen       0
10      9    19 žena    ZŠ       ne    nepracuje kouří   nečlen     0
11      3    18 žena    ZŠ       ne    nepracuje kouří   nečlen     0

Příklad 13

Vytvořte proměnnou s názvem Pohlaví_Vzdělání, která v sobě bude obsahovat údaje z obou těchto proměnných. Tuto proměnnou následně připojte k databázi Katan.

Pohlaví_Vzdělání <- paste(
    Katan$Pohlaví, 
    Katan$Vzdělání)

Katan$Pohlaví_Vzdělání <- Pohlaví_Vzdělání
Katan[, c(1:6, 10)]
# A tibble: 200 x 7
   Partie   Věk Pohlaví Vzdělání Kolej Práce     Pohlaví_Vzdělání
    <dbl> <dbl> <chr>   <chr>    <chr> <chr>     <chr>           
 1      4    13 žena    ZŠ       ne    nepracuje žena ZŠ         
 2      4    13 žena    ZŠ       ne    nepracuje žena ZŠ         
 3      3    14 muž     ZŠ       ne    nepracuje muž ZŠ          
 4      8    14 muž     ZŠ       ne    nepracuje muž ZŠ          
 5      5    15 muž     ZŠ       ne    nepracuje muž ZŠ          
 6      6    15 muž     ZŠ       ne    nepracuje muž ZŠ          
 7      6    15 muž     ZŠ       ne    nepracuje muž ZŠ          
 8      3    15 žena    ZŠ       ne    nepracuje žena ZŠ         
 9      3    15 žena    ZŠ       ne    nepracuje žena ZŠ         
10      9    15 žena    ZŠ       ne    nepracuje žena ZŠ         
# ... with 190 more rows

Příklad 14

Výše uvedenou proměnnou Pohlaví_Vzdělání odstraňte z databáze Katan2.

Katan$Pohlaví_Vzdělání <- NULL

Příklad 15

Vytvořte Databázi A, která obsahuje dvě proměnné. Tou první bude proměnná ID, jež obsahuje čísla od jedné do 30 (náhodně uspořádaná, na příkaz 1:30 tudíž zapomeňte). Tou druhou proměnnou bude zeměpis, která obsahuje náhodný vektor známek z písemky. Následně vytvořte obdobnou Databázi B, která bude naopak obsahovat známky z matematiky. Vaším úkolem bude tyto dvě databáze spojit podle proměnné ID. A aby to nebylo tak jednoduché, známky z jednotlivých předmětů se budou vyskytovat s následující pravděpodobností (1: 30 %; 2: 50 %; 3: 10 %; 4: 5 %; 5: 5 %). Jak je vidět, pan učitel byl velice mírný.

Databáze_A <- data.frame(
  ID = sample(30, size = 30, replace = FALSE),
  Zeměpis = sample(1:5, size = 30, replace = TRUE, prob=c(.30, .50, .10, .5, .5)))

Databáze_B <- data.frame(
  ID = sample(30, size = 30, replace = FALSE),
  Matematika = sample(1:5, size = 30, replace = TRUE, prob=c(.30, .50, .10, .5, .5)))

MergeData <-
  merge(Databáze_A, Databáze_B[ , c("ID", "Zeměpis", "Matematika")], by = "ID")
   ID Zeměpis Matematika
1   1       2          2
2   2       2          1
3   3       3          2
4   4       2          1
5   5       3          2
6   6       5          2
7   7       2          1
8   8       2          1
9   9       2          1
10 10       2          2
11 11       2          5
12 12       1          2
13 13       3          3
14 14       2          4
15 15       1          2
16 16       5          2
17 17       1          1
18 18       2          4
19 19       3          2
20 20       2          2
21 21       1          1
22 22       1          2
23 23       2          2
24 24       1          1
25 25       5          1
26 26       2          1
27 27       5          2
28 28       3          2
29 29       3          2
30 30       2          2

Příklad 16

Vypočítejte průměr proměnné Partie podle pohlaví a vzdělání.

aggregate(
    Katan$Partie,
    list(Katan$Pohlaví, 
         Katan$Vzdělání),
    FUN = mean, 
    simplify = TRUE, 
    na.rm = TRUE)
  Group.1 Group.2        x
1     muž Bc - VŠ 3.666667
2    žena Bc - VŠ 2.692308
3     muž      SŠ 2.828571
4    žena      SŠ 4.260870
5     muž      VŠ 1.634146
6    žena      VŠ 2.444444
7     muž      ZŠ 4.360000
8    žena      ZŠ 5.230769

Příklad 17

Vypočítejte medián proměnné Věk podle pohlaví a kouření.

aggregate(
    Katan$Věk,
    list(Katan$Pohlaví, 
         Katan$Kouření),
    FUN = median, 
    simplify = TRUE, 
    na.rm = TRUE)
  Group.1 Group.2    x
1     muž   kouří 30.0
2    žena   kouří 24.5
3     muž nekouří 26.0
4    žena nekouří 21.0

Příklad 18

Vypočítejte průměr proměnné Partie podle pohlaví a vzdělání u jedinců, kteří mají alespoň jedno dítě.

aggregate(
  Katan$Partie,
  list(Katan$Pohlaví, 
       Katan$Vzdělání, 
       Katan$Děti >= 1),
  FUN = mean, 
  simplify = TRUE, 
  na.rm = TRUE)

# nebo

tapply(
  Katan$Partie,
  list(Katan$Pohlaví, 
       Katan$Vzdělání, 
       Katan$Děti >= 1),
  mean, 
  simplify = TRUE)
   Group.1 Group.2 Group.3        x
1      muž Bc - VŠ   FALSE 3.666667
2     žena Bc - VŠ   FALSE 2.692308
3      muž      SŠ   FALSE 4.000000
4     žena      SŠ   FALSE 4.409091
5      muž      VŠ   FALSE 1.500000
6     žena      VŠ   FALSE 2.500000
7      muž      ZŠ   FALSE 5.100000
8     žena      ZŠ   FALSE 5.230769
9      muž      SŠ    TRUE 1.588235
10    žena      SŠ    TRUE 1.000000
11     muž      VŠ    TRUE 1.677419
12    žena      VŠ    TRUE 2.000000
13     muž      ZŠ    TRUE 1.400000
, , FALSE

      Bc - VŠ       SŠ  VŠ       ZŠ
muž  3.666667 4.000000 1.5 5.100000
žena 2.692308 4.409091 2.5 5.230769

, , TRUE

     Bc - VŠ       SŠ       VŠ  ZŠ
muž       NA 1.588235 1.677419 1.4
žena      NA 1.000000 2.000000  NA

Příklad 19

Vytáhněte si rukávy, je tu pro vás připraven jeden docela komplikovaný příklad. Vaším úkolem bude vytvořit funkci s názvem mzdová_kalkulačka. Ta po udání hrubé mzdy vypočítá náklady zaměstnance na sociální pojištění, zdravotní pojištění a daň z příjmů fyzických osob.

Následně vytvořte tři náhodné vektory o sto položkách hodnot, které budou obsahovat údaje o hrubé mzdě, počtu dětí a manželce (nebo manželovi), jejíž (jehož) příjem je nižší než 68 000 Kč za rok (1: ano, 0: ne). Poté pomocí funkce mzdová_kalkulačka vypočítejte výše uvedená pojištění a daň z příjmů. Závěrem vytvořte data frame, který bude obsahovat sedm sloupců: hrubá mzda, čistá mzda, počet dětí, manžel(ka), sociální pojištění, zdravotní pojištění a daň z příjmů.

Pozn. sociální pojištění: 6,5 % z hrubé mzdy; zdravotní pojištění: 4,5 % z hrubé mzdy; daň z příjmů: 15 % ze superhrubé mzdy; superhrubá mzda: hrubá mzda * 1,34; daňová sleva na každého poplatníka: 2 070 Kč; daňová sleva na manžela(ku): 2 070 Kč; daňová sleva na dítě: 1. dítě = 1 267 Kč měsíčně, 2. dítě = 1 617 Kč, 3. a každé další dítě = 2 017 Kč.

Pro zjednodušení uvažujte, že sleva na dítě činí 1 500 Kč na všechny děti. Dosud jsme totiž neprobírali podmínku IF, bez jejíž pomoci byste tento problém nemohli vyřešit. Ta se stane předmětem našeho zájmu v příští kapitole.

V příkladu se nezapomeňte vypořádat s tím, že sleva na poplatníka a manželku může snížit daň maximálně na nulu, zatímco slevy na dítě se mohou přetvořit v tzv. daňový bonus, tj. daň může být záporná. Uveďme si příklad. Daň z příjmů byla u jedince, jenž má nárok na slevu na manželku, vypočítána na hodnotu 3 000 Kč. Sleva na poplatníka a manželku činí dohromady 4 140 Kč. Daň však nemůže jít do záporných hodnot, proto bude činit nula. V případě, že ale takový člověk měl například dvě děti, bude mu vypočítán daňový bonus ve výši 2 884 Kč (respektive v našem příkladu 3 000 Kč).

mzdová_kalkulačka <- function(Hrubá_mzda, Manželka = 0, Děti = 0) {
  sociální <- 0.065 * Hrubá_mzda
  zdravotní <- 0.045 * Hrubá_mzda
  daň <- (0.15 * (Hrubá_mzda * 1.34) - 2070 - (Manželka * 2070))
  daň[daň < 0] <- 0
  daň <- daň - (Děti * 1500)
  cmzda <- Hrubá_mzda - sociální - zdravotní - daň
  
  return(data.frame(Hrubá_mzda,
                    "Čistá_mzda" = cmzda,
                    Manželka,
                    Děti,
                    "Sociální_pojištění" = sociální, 
                    "Zdravotní_pojištění" = zdravotní, 
                    "Daň_z_příjmu" = daň))
}

Hrubá_mzda <- sample(18000:50000, size = 100, replace = TRUE)
Manželka <- sample(c(0,1), size = 100, replace = TRUE)
Děti <- sample(0:4, size = 100, replace = TRUE)
mzdy <- data.frame(Hrubá_mzda,Manželka,Děti)

Data <- mzdová_kalkulačka(mzdy$Hrubá_mzda, mzdy$Manželka, mzdy$Děti)
    Hrubá_mzda Čistá_mzda Manželka Děti Sociální_pojištění Zdravotní_pojištění
1        31727   29929.90        0    4           2062.255            1427.715
2        38944   34902.42        0    4           2531.360            1752.480
3        18439   19274.47        0    3           1198.535             829.755
4        35911   34882.68        1    4           2334.215            1615.995
5        24151   23210.04        0    3           1569.815            1086.795
6        40385   31965.26        1    0           2625.025            1817.325
7        23054   20954.21        0    2           1498.510            1037.430
8        45034   38168.43        1    2           2927.210            2026.530
9        41541   30691.75        0    0           2700.165            1869.345
10       18133   19138.37        1    2           1178.645             815.985
11       22610   21218.29        1    1           1469.650            1017.450
12       48715   41634.63        0    4           3166.475            2192.175
13       47689   36997.72        1    0           3099.785            2146.005
14       36935   35588.22        1    4           2400.775            1662.075
15       49748   36346.37        0    0           3233.620            2238.660
16       20545   18285.05        1    0           1335.425             924.525
17       49156   37438.48        0    1           3195.140            2212.020
18       30895   24856.65        0    1           2008.175            1390.275
19       26352   28296.53        1    4           1712.880            1185.840
20       41289   35018.12        0    3           2683.785            1858.005
21       20061   15892.03        0    0           1303.965             902.745
22       48232   39801.85        0    3           3135.080            2170.440
23       48212   41858.07        1    3           3133.780            2169.540
24       22755   24318.19        1    3           1479.075            1023.975
25       34086   29125.25        1    1           2215.590            1533.870
26       45720   39571.08        0    4           2971.800            2057.400
27       44029   35975.98        1    1           2861.885            1981.305
28       41387   33585.64        0    2           2690.155            1862.415
29       24570   27068.73        1    4           1597.050            1105.650
30       49955   41559.00        1    2           3247.075            2247.975
31       24754   20625.51        0    1           1609.010            1113.930
32       44857   39546.47        1    3           2915.705            2018.565
33       20445   19156.60        0    2           1328.925             920.025
34       49231   44060.16        1    4           3200.015            2215.395
35       28368   24615.55        0    2           1843.920            1276.560
36       32138   25713.08        0    1           2088.970            1446.210
37       19629   20094.38        0    3           1275.885             883.305
38       34237   30729.29        1    2           2225.405            1540.665
39       21301   19746.39        0    2           1384.565             958.545
40       43769   37296.84        1    2           2844.985            1969.605
41       38364   31502.80        0    2           2493.660            1726.380
42       47778   34989.04        0    0           3105.570            2150.010
43       45747   39589.68        0    4           2973.555            2058.615
44       47805   37077.65        1    0           3107.325            2151.225
45       45200   39782.80        1    3           2938.000            2034.000
46       43672   36660.01        0    3           2838.680            1965.240
47       30433   27538.34        0    3           1978.145            1369.485
48       36125   28460.12        0    1           2348.125            1625.625
49       34432   27293.65        0    1           2238.080            1549.440
50       23724   20485.84        1    0           1542.060            1067.580
51       41403   36596.67        0    4           2691.195            1863.135
52       47429   37748.58        0    2           3082.885            2134.305
53       36791   33419.00        0    4           2391.415            1655.595
54       37310   32846.59        1    2           2425.150            1678.950
55       48170   36759.13        0    1           3131.050            2167.650
56       24735   22112.41        0    2           1607.775            1113.075
57       21266   20292.27        1    1           1382.290             956.970
58       36708   27361.81        0    0           2386.020            1651.860
59       34183   32192.09        1    3           2221.895            1538.235
60       31274   23617.79        0    0           2032.810            1407.330
61       39342   35746.64        1    3           2557.230            1770.390
62       40280   34322.92        0    3           2618.200            1812.600
63       37631   30997.76        0    2           2446.015            1693.395
64       25486   23199.85        1    1           1656.590            1146.870
65       37820   30197.98        1    0           2458.300            1701.900
66       46641   40205.65        0    4           3031.665            2098.845
67       20493   22738.77        1    3           1332.045             922.185
68       30672   29203.01        0    4           1993.680            1380.240
69       23076   23039.36        1    2           1499.940            1038.420
70       32180   28742.02        0    3           2091.700            1448.100
71       40018   34712.40        1    2           2601.170            1800.810
72       43595   36606.95        0    3           2833.675            1961.775
73       47280   39145.92        0    3           3073.200            2127.600
74       38955   32480.00        1    1           2532.075            1752.975
75       28698   25412.92        1    1           1865.370            1291.410
76       25102   21435.28        1    0           1631.630            1129.590
77       45669   38035.94        0    3           2968.485            2055.105
78       44397   37159.53        0    3           2885.805            1997.865
79       20916   23051.12        1    3           1359.540             941.220
80       19415   19946.94        0    3           1261.975             873.675
81       29911   25678.68        0    2           1944.215            1345.995
82       41423   36610.45        0    4           2692.495            1864.035
83       25667   24824.56        1    2           1668.355            1155.015
84       29322   23772.86        0    1           1905.930            1319.490
85       45028   41164.29        1    4           2926.820            2026.260
86       47795   39500.75        0    3           3106.675            2150.775
87       42088   35568.63        0    3           2735.720            1893.960
88       22372   18984.31        0    1           1454.180            1006.740
89       31269   29614.34        0    4           2032.485            1407.105
90       40451   36510.74        1    3           2629.315            1820.295
91       18280   17769.20        1    1           1188.200             822.600
92       40056   29668.58        0    0           2603.640            1802.520
93       46119   38345.99        0    3           2997.735            2075.355
94       27903   27295.17        0    4           1813.695            1255.635
95       41623   33748.25        0    2           2705.495            1873.035
96       25520   22653.28        0    2           1658.800            1148.400
97       38591   34659.20        0    4           2508.415            1736.595
98       44692   32862.79        0    0           2904.980            2011.140
99       31648   28945.47        1    2           2057.120            1424.160
100      31434   31798.03        1    4           2043.210            1414.530
    Daň_z_příjmu
1      -1692.873
2       -242.256
3      -2863.761
4      -2921.889
5      -1715.649
6       3977.385
7       -436.146
8       1911.834
9       6279.741
10     -3000.000
11     -1095.390
12      1721.715
13      5445.489
14     -2716.065
15      7929.348
16         0.000
17      6310.356
18      2639.895
19     -4843.248
20      1729.089
21      1962.261
22      3124.632
23      1050.612
24     -4066.245
25      1211.286
26      1119.720
27      3209.829
28      3248.787
29     -5201.430
30      2900.955
31      1405.554
32       376.257
33      -960.555
34      -244.569
35       631.968
36      2889.738
37     -2624.571
38      -258.363
39      -788.499
40      1657.569
41      2641.164
42      7533.378
43      1125.147
44      5468.805
45       445.200
46      2208.072
47      -452.967
48      3691.125
49      3350.832
50       628.524
51       252.003
52      4463.229
53      -675.009
54       359.310
55      6112.170
56       -98.265
57     -1365.534
58      5308.308
59     -1769.217
60      4216.074
61      -732.258
62      1526.280
63      2493.831
64      -517.314
65      3461.820
66      1304.841
67     -4500.000
68     -1904.928
69     -2501.724
70      -101.820
71       903.618
72      2192.595
73      2933.280
74      2189.955
75       128.298
76       905.502
77      2609.469
78      2353.797
79     -4435.884
80     -2667.585
81       942.111
82       256.023
83     -1980.933
84      2323.722
85     -1089.372
86      3036.795
87      1889.688
88       926.772
89     -1784.931
90      -509.349
91     -1500.000
92      5981.256
93      2699.919
94     -2461.497
95      3296.223
96        59.520
97      -313.209
98      6913.092
99      -778.752
100    -3821.766

Column